home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
C
/
Applications
/
Python 1.3.3
/
Python 133 SRC
/
Extensions
/
img
/
imgtiffmodule.c
< prev
Wrap
Text File
|
1995-12-21
|
20KB
|
766 lines
/***********************************************************
Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
Amsterdam, The Netherlands.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the names of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
/*
** Partially derived from tifftopnm.c and pnmtotiff.c, which were written
** by Jeff Poskanzer, who in turn derived them from ras2tif.c and tis2ras.c,
** which are:
**
** Copyright (c) 1990 by Sun Microsystems, Inc.
**
** Author: Patrick J. Naughton
** naughton@wind.sun.com
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation.
**
** This file is provided AS IS with no warranties of any kind. The author
** shall have no liability with respect to the infringement of copyrights,
** trade secrets or any patents by this file or any part thereof. In no
** event will the author be liable for any lost revenue or profits or
** other special, indirect and consequential damages.
*/
/*
** Note: the code could do with some optimalization. The inner loop
** in tiff_read() is rather big and contains multiple special cases,
** which could be separated out or something. Oh well, It'll be faster
** than decoding tiff files in python:-)
*/
#include "allobjects.h"
#include "modsupport.h" /* For getargs() etc. */
#include "import.h"
#include "tiffio.h"
/* The image formats we support */
static PyObject *format_rgb, *format_rgb_b2t, *format_grey,
*format_grey_b2t, *format_choices;
extern PyObject *getimgformat(); /* Get format by name */
/* TIFF error handling */
char tifferrstr[1000];
static TIFFErrorHandler prevErr;
static TIFFErrorHandler prevWarn;
#define TIFF_END TIFFSetErrorHandler(prevErr); TIFFSetWarningHandler(prevWarn);
#define TIFF_START prevErr = TIFFSetErrorHandler(my_tifferror); \
prevWarn = TIFFSetWarningHandler(my_tiffwarning);
static void
my_tiffwarning(const char *module, const char *fmt, va_list ap)
{
/* Ignore warnings */
}
static void
my_tifferror(const char *module, const char *fmt, va_list ap)
{
char *ptr = tifferrstr;
if ( module ) {
sprintf(ptr, "%s: ", module);
ptr += strlen(ptr);
}
vsprintf(ptr, fmt, ap);
}
/* Tiff objects */
typedef int tifpix; /* I assume this is correct? Always? */
typedef struct {
PyObject_HEAD
PyObject *dict; /* Attributes dictionary */
int is_reader; /* TRUE if this is a reader */
char *filename; /* filename of the image file */
TIFF *filep;
tifpix maxval; /* Max pixel value in tiff file */
float factor; /* Convert maxval to 0xff */
unsigned short photomet;/* TIFF "filetype" */
unsigned short bps; /* bits per sample */
unsigned short spp; /* samples per pixel */
} tiffobject;
static PyObject *errobject;
staticforward PyTypeObject Tifftype;
#define is_tiffobject(v) ((v)->ob_type == &Tifftype)
static char doc_tiff[] = "This object reads/writes TIFF files.\n"
"The 'width', 'height' and 'format' attributes give info about the\n"
"image data read (or to be written)";
/* Routine to easily obtain C data from the dict python data */
int
tiffselfattr(self, name, fmt, ptr, wanterr)
tiffobject *self;
char *name;
char *fmt;
void *ptr;
int wanterr;
{
PyObject *obj;
char errbuf[100];
obj = PyDict_GetItemString(self->dict, name);
if ( obj == NULL ) {
if ( wanterr ) {
sprintf(errbuf, "Required attribute '%s' not set", name);
PyErr_SetString(errobject, errbuf);
return 0;
} else {
PyErr_Clear();
return 0;
}
}
if ( !PyArg_Parse(obj, fmt, ptr) ) {
if ( !wanterr )
PyErr_Clear();
return 0;
}
return 1;
}
/* Routine to easily insert integer into dictionary */
tiffsetintattr(self, name, value)
tiffobject *self;
char *name;
int value;
{
PyObject *obj;
int rv;
obj = PyInt_FromLong(value);
rv = PyDict_SetItemString(self->dict, name, obj);
Py_DECREF(obj);
return rv;
}
static tiffobject *
newtiffobject()
{
tiffobject *xp;
xp = PyObject_NEW(tiffobject, &Tifftype);
if (xp == NULL)
return NULL;
xp->dict = PyDict_New();
xp->filename = NULL;
xp->filep = NULL;
return xp;
}
static int
inittiffreader(self, name)
tiffobject *self;
char *name;
{
char *name_copy;
int cols, rows;
unsigned short bps, spp, photomet;
tifpix maxval;
PyObject *ourformat;
if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
PyErr_NoMemory();
return 0;
}
strcpy(name_copy, name);
self->filename = name_copy;
self->is_reader = 1;
TIFF_START
if ((self->filep = TIFFOpen(self->filename, "r")) == NULL ) {
PyErr_SetString(errobject, tifferrstr);
TIFF_END
return 0;
}
if ( ! TIFFGetField( self->filep, TIFFTAG_BITSPERSAMPLE, &bps ) )
bps = 1;
if ( ! TIFFGetField( self->filep, TIFFTAG_SAMPLESPERPIXEL, &spp ) )
spp = 1;
if ( ! TIFFGetField( self->filep, TIFFTAG_PHOTOMETRIC, &photomet ) ) {
PyErr_SetString(errobject, "No photometric tag");
TIFF_END
return 0;
}
switch ( spp ) {
case 1:
case 3:
case 4:
break;
default:
PyErr_SetString(errobject,
"can only handle 1-channel gray scale or 1- or 3-channel color" );
TIFF_END
return 0;
}
(void) TIFFGetField( self->filep, TIFFTAG_IMAGEWIDTH, &cols );
(void) TIFFGetField( self->filep, TIFFTAG_IMAGELENGTH, &rows );
TIFF_END
maxval = ( 1 << bps ) - 1;
self->maxval = maxval;
if ( maxval != 255 ) {
self->factor = 255.0/(float)maxval;
/*DBG printf("TIFF factor: %e (%d)\n", self->factor, maxval); */
}
self->bps = bps;
self->spp = spp;
self->photomet = photomet;
if ( maxval == 1 && spp == 1 ) {
ourformat = format_grey;
} else {
switch ( photomet ) {
case PHOTOMETRIC_MINISBLACK:
ourformat = format_grey;
break;
case PHOTOMETRIC_MINISWHITE:
ourformat = format_grey;
break;
case PHOTOMETRIC_PALETTE:
PyErr_SetString(errobject, "Cannot handle PALETTE format yet");
return 0;
case PHOTOMETRIC_RGB:
ourformat = format_rgb;
break;
case PHOTOMETRIC_MASK:
PyErr_SetString(errobject, "Cannot handle PHOTOMETRIC_MASK" );
return 0;
default:
PyErr_SetString(errobject, "Unknown photometric type");
return 0;
}
}
TIFF_END
tiffsetintattr(self, "width", cols);
tiffsetintattr(self, "height", rows);
#if 0
tiffsetintattr(self, "bps", (int)bps);
tiffsetintattr(self, "spp", (int)spp);
#endif
PyDict_SetItemString(self->dict, "format", ourformat);
PyDict_SetItemString(self->dict, "format_choices", format_choices);
if ( PyErr_Occurred() )
return 0;
return 1;
}
static int
inittiffwriter(self, name)
tiffobject *self;
char *name;
{
char *name_copy;
if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
PyErr_NoMemory();
return 0;
}
strcpy(name_copy, name);
self->filename = name_copy;
self->is_reader = 0;
PyDict_SetItemString(self->dict, "format", format_rgb);
PyDict_SetItemString(self->dict, "format_choices", format_choices);
if( PyErr_Occurred())
return 0;
return 1;
}
/* Tiff methods */
static void
tiff_dealloc(xp)
tiffobject *xp;
{
Py_XDECREF(xp->dict);
if( xp->filename )
free(xp->filename);
if( xp->filep )
TIFFClose(xp->filep);
PyMem_DEL(xp);
}
static char doc_read[] = "Read the actual data, returns a string";
static PyObject *
tiff_read(self, args)
tiffobject *self;
PyObject *args;
{
int w, h, toptobottom, havegrey, wantgrey, rowlen;
int row, col, bitsleft;
PyObject *rv;
long *rgbdatap=0;
char *greydatap=0;
tifpix greysample, redsample, greensample, bluesample, maxval;
PyObject *fmt;
unsigned char *buf, *inP;
unsigned short bps, spp, photomet;
if (!PyArg_ParseTuple(args,""))
return NULL;
if (!self->is_reader) {
PyErr_SetString(errobject, "Cannot read() from writer object");
return NULL;
}
/* XXXX Read data and return it */
/* XXXX Get args from self->dict and write the data */
if ( !tiffselfattr(self, "width", "i", &w, 1) ||
!tiffselfattr(self, "height", "i", &h, 1) ||
!tiffselfattr(self, "format", "O", &fmt, 1) )
return NULL;
if ( fmt == format_rgb || fmt == format_grey )
toptobottom = 1;
else if ( fmt == format_rgb_b2t || fmt == format_grey_b2t )
toptobottom = 0;
else {
PyErr_SetString(errobject, "Unsupported image format");
return NULL;
}
if ( fmt == format_rgb || fmt == format_rgb_b2t )
wantgrey = 0;
else
wantgrey = 1;
rv = 0;
rowlen = w;
if ( wantgrey ) {
rowlen = (rowlen+3) & ~3; /* pad to 32-bit boundary */
if ( (rv=PyString_FromStringAndSize(0, rowlen*h)) == NULL )
return NULL;
greydatap = PyString_AsString(rv);
rgbdatap = 0;
} else {
if ( (rv=PyString_FromStringAndSize(0, rowlen*h*4)) == NULL )
return NULL;
rgbdatap = (long *)PyString_AsString(rv);
greydatap = 0;
}
if ( !toptobottom ) {
greydatap = greydatap + rowlen*(h-1);
rgbdatap = rgbdatap + rowlen*(h-1);
rowlen = -rowlen;
}
havegrey = (self->photomet != PHOTOMETRIC_RGB);
bps = self->bps;
maxval = self->maxval;
spp = self->spp;
photomet = self->photomet;
buf = (unsigned char *)malloc(TIFFScanlineSize(self->filep));
if ( buf == NULL ) {
Py_DECREF(rv);
PyErr_NoMemory();
return NULL;
}
TIFF_START
#define NEXTSAMPLE(which) \
{ \
if ( bitsleft == 0 ) \
{ \
++inP; \
bitsleft = 8; \
} \
bitsleft -= bps; \
which = ( *inP >> bitsleft ) & maxval; \
}
row = 0;
while( row < h ) {
if ( TIFFReadScanline( self->filep, buf, row, 0) < 0) {
PyErr_SetString(errobject, tifferrstr);
free(buf);
TIFF_END
return NULL;
}
inP = buf;
bitsleft = 8;
for( col=0; col<w; col++ ) {
switch(photomet) {
case PHOTOMETRIC_MINISBLACK:
NEXTSAMPLE(greysample);
break;
case PHOTOMETRIC_MINISWHITE:
NEXTSAMPLE(greysample);
greysample = maxval - greysample;
break;
case PHOTOMETRIC_RGB:
NEXTSAMPLE(redsample);
NEXTSAMPLE(greensample);
NEXTSAMPLE(bluesample);
if ( spp == 4 )
NEXTSAMPLE(greysample); /* Ignored alpha */
break;
default:
PyErr_SetString(errobject, "Unknown photometric (cannot happen)");
free(buf);
TIFF_END
return NULL;
}
if ( !havegrey && wantgrey ) {
greysample = (int)(0.299*redsample+0.587*greensample+
0.114*bluesample);
if ( greysample > 255 ) greysample = 255;
} else if ( havegrey && !wantgrey ) {
redsample = greensample = bluesample = greysample;
}
if ( wantgrey ) {
if ( maxval != 255 ) {
greysample = (int)((float)greysample*self->factor);
if ( greysample > 255 )
greysample = 255;
}
greydatap[col] = greysample;
} else {
if ( maxval != 255 ) {
redsample = (int)((float)redsample*self->factor);
if ( redsample > 255 )
redsample = 255;
greensample = (int)((float)greensample*self->factor);
if ( greensample > 255 )
greensample = 255;
bluesample = (int)((float)bluesample*self->factor);
if ( bluesample > 255 )
bluesample = 255;
}
rgbdatap[col] = redsample | (greensample<<8) |
(bluesample<<16);
}
}
/* Zero-out remaining bytes */
if ( wantgrey )
while( col < rowlen )
greydatap[col++] = 0;
rgbdatap += rowlen;
greydatap += rowlen;
row++;
}
TIFF_END
free(buf);
return rv;
}
static char doc_write[] = "Write (string) data to the TIFF file.";
static PyObject *
tiff_write(self, args)
tiffobject *self;
PyObject *args;
{
long *rgbdata;
char *greydata;
int datalen, lenwanted;
unsigned char *buf, *tP;
int i, w, h, rowlen, row;
PyObject *fmt;
long rgbpixel;
unsigned short photomet, spp;
int bytesperrow;
long rowsperstrip;
TIFF *filep;
if (!PyArg_ParseTuple(args, "s#", &greydata, &datalen))
return NULL;
if (self->is_reader) {
PyErr_SetString(errobject, "Cannot write() to reader object");
return NULL;
}
/* XXXX Get args from self->dict and write the data */
if ( !tiffselfattr(self, "width", "i", &w, 1) ||
!tiffselfattr(self, "height", "i", &h, 1) ||
!tiffselfattr(self, "format", "O", &fmt, 1) )
return NULL;
rowlen = w;
if ( fmt == format_rgb || fmt == format_rgb_b2t ) {
spp = 3;
photomet = PHOTOMETRIC_RGB;
lenwanted = w*h*4;
rgbdata = (long *)greydata;
greydata = 0;
} else if ( fmt == format_grey || fmt == format_grey_b2t ) {
spp = 1;
photomet = PHOTOMETRIC_MINISBLACK;
rowlen = (w+3) &~3;
lenwanted = rowlen*h;
rgbdata = 0;
} else {
PyErr_SetString(errobject, "Unsupported image format");
return NULL;
}
if( datalen != lenwanted ) {
PyErr_SetString(errobject, "Incorrect datasize");
return NULL;
}
if ( fmt == format_rgb_b2t || fmt == format_grey_b2t ) {
rgbdata = rgbdata + rowlen*(h-1);
greydata = greydata + rowlen*(h-1);
rowlen = -rowlen;
}
bytesperrow = spp*w;
rowsperstrip = 8192 / bytesperrow; /* ??? from pnmtotiff */
if( (buf = malloc(bytesperrow)) == NULL ) {
PyErr_NoMemory();
return NULL;
}
TIFF_START
if ((filep = TIFFOpen(self->filename, "w")) == NULL) {
PyErr_SetString(errobject, tifferrstr);
TIFF_END
return 0;
}
TIFFSetField(filep, TIFFTAG_IMAGEWIDTH, w);
TIFFSetField(filep, TIFFTAG_IMAGELENGTH, h);
TIFFSetField(filep, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(filep, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); /*XXX*/
TIFFSetField(filep, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
TIFFSetField(filep, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
TIFFSetField(filep, TIFFTAG_PHOTOMETRIC, photomet);
TIFFSetField(filep, TIFFTAG_SAMPLESPERPIXEL, spp);
TIFFSetField(filep, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
TIFFSetField(filep, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(filep, TIFFTAG_SOFTWARE, "Python TIFF module");
row = 0;
while( row < h ) {
tP = buf;
for(i=0; i<w; i++) {
if ( photomet == PHOTOMETRIC_RGB ) {
rgbpixel = rgbdata[i];
*tP++ = rgbpixel & 0xff;
*tP++ = (rgbpixel>>8) & 0xff;
*tP++ = (rgbpixel>>16) & 0xff;
} else {
*tP++ = greydata[i];
}
}
if ( TIFFWriteScanline(filep, buf, row, 0) < 0 ) {
free(buf);
PyErr_SetString(errobject, tifferrstr);
return 0;
}
rgbdata += rowlen;
greydata += rowlen;
row = row+1;
}
TIFFFlushData(filep);
TIFFClose(filep);
free(buf);
Py_INCREF(Py_None);
return Py_None;
}
static struct PyMethodDef tiff_methods[] = {
{"read", (PyCFunction)tiff_read, 1, doc_read},
{"write", (PyCFunction)tiff_write, 1, doc_write},
{NULL, NULL} /* sentinel */
};
static PyObject *
tiff_getattr(xp, name)
tiffobject *xp;
char *name;
{
PyObject *v;
if (xp->dict != NULL) {
if ( strcmp(name, "__dict__") == 0 ) {
Py_INCREF(xp->dict);
return xp->dict;
}
if ( strcmp(name, "__doc__") == 0 ) {
return PyString_FromString(doc_tiff);
}
v = PyDict_GetItemString(xp->dict, name);
if (v != NULL) {
Py_INCREF(v);
return v;
}
}
return Py_FindMethod(tiff_methods, (PyObject *)xp, name);
}
static int
tiff_setattr(xp, name, v)
tiffobject *xp;
char *name;
PyObject *v;
{
if (xp->dict == NULL) {
xp->dict = PyDict_New();
if (xp->dict == NULL)
return -1;
}
if (v == NULL) {
int rv = PyDict_DelItemString(xp->dict, name);
if (rv < 0)
PyErr_SetString(PyExc_AttributeError,
"delete non-existing imgtiff attribute");
return rv;
}
else
return PyDict_SetItemString(xp->dict, name, v);
}
static PyTypeObject Tifftype = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"imgtiff", /*tp_name*/
sizeof(tiffobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)tiff_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)tiff_getattr, /*tp_getattr*/
(setattrfunc)tiff_setattr, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
};
static char doc_newreader[] =
"Return an object that reads the TIFF file passed as argument";
static PyObject *
tiff_newreader(self, args)
PyObject *self;
PyObject *args;
{
char *filename;
tiffobject *obj;
if (!PyArg_ParseTuple(args, "s", &filename))
return NULL;
if ((obj = newtiffobject()) == NULL)
return NULL;
if ( !inittiffreader(obj, filename) ) {
tiff_dealloc(obj);
return NULL;
}
return (PyObject *)obj;
}
static char doc_newwriter[] =
"Return an object that writes the TIFF file passed as argument";
static PyObject *
tiff_newwriter(self, args)
PyObject *self;
PyObject *args;
{
char *filename;
tiffobject *obj;
if (!PyArg_ParseTuple(args, "s", &filename))
return NULL;
if ((obj = newtiffobject()) == NULL)
return NULL;
if ( !inittiffwriter(obj, filename) ) {
tiff_dealloc(obj);
return NULL;
}
return (PyObject *)obj;
}
/* List of functions defined in the module */
static struct PyMethodDef tiff_module_methods[] = {
{"reader", tiff_newreader, 1, doc_newreader},
{"writer", tiff_newwriter, 1, doc_newwriter},
{NULL, NULL} /* sentinel */
};
/* Initialization function for the module (*must* be called initimgtiff) */
static char doc_imgtiff[] = "Module to read and write TIFF image files";
void
initimgtiff()
{
PyObject *m, *d, *x, *formatmodule, *formatdict;
/* Create the module and add the functions */
m = Py_InitModule("imgtiff", tiff_module_methods);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
errobject = PyString_FromString("imgtiff.error");
PyDict_SetItemString(d, "error", errobject);
x = PyString_FromString(doc_imgtiff);
PyDict_SetItemString(d, "__doc__", x);
/* Get supported formats */
if ((formatmodule = PyImport_ImportModule("imgformat")) == NULL)
Py_FatalError("imgtiff depends on imgformat");
if ((formatdict = PyModule_GetDict(formatmodule)) == NULL)
Py_FatalError("imgformat has no dict");
format_rgb = PyDict_GetItemString(formatdict,"rgb");
format_rgb_b2t = PyDict_GetItemString(formatdict,"rgb_b2t");
format_grey = PyDict_GetItemString(formatdict,"grey");
format_grey_b2t = PyDict_GetItemString(formatdict,"grey_b2t");
format_choices = Py_BuildValue("(OOOO)", format_rgb, format_rgb_b2t,
format_grey, format_grey_b2t);
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module imgtiff");
}